package com.example.gcmtest1.youtube;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.net.URLDecoder;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONStringer;

import com.example.gcmtest1.FileListActivity;
import com.example.gcmtest1.R;
import com.example.gcmtest1.YoutubeActivity;
import com.example.gcmtest1.httpserver.HTTPProxyService;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.net.UrlQuerySanitizer;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

public class YoutubeDownloader extends AsyncTask<String, Integer, Long> implements DialogInterface.OnClickListener {

	public static String[] PARAMS = {"factor", "algorithm", "burst", "newshard", "ratebypass", "gcr", "ipbits", "id", "sver", "ip", "cp", "ms", "fexp", "mv", "upn", "mt", "sparams", "source", "key", "expire", "itag", "signature"};
	private String logName = "YoutubeDownloader";
	private String firstUrl, youtubeQString;
	private Context context;
	
	private ArrayList<RealLink> aLinks;
	private ProgressDialog pgDialog;
	private AlertDialog alertDialog;
	
	private SmartHTTPDownload dl;
	private String title;
	    
	public YoutubeDownloader(Context context, String firstUrl) {
		this.context = context;
		this.firstUrl = firstUrl;
				
		UrlQuerySanitizer qq = new UrlQuerySanitizer(firstUrl);
		this.youtubeQString = qq.getValue("v");
		Log.d(logName, "youtubeQString=" + this.youtubeQString);
		
		String realUrl = this.getRealUrl("http://r6---sn-uvu-c33e.c.youtube.com/videoplayback?&newshard=yes&ratebypass=yes&gcr=th&ipbits=8&id=f5b664a7b");
		Log.d(logName, "realUrl: " + realUrl);
	}
	
	
	public void publishProgress(Integer value) {
		super.publishProgress(value);
		final Integer finalValue = value;
	
		/*
		if (this.dl != null) {
			if (this.dl.pgbFileDownload != null) {
				this.dl.pgbFileDownload.setProgress(value);
				
				
				((Activity) this.context).runOnUiThread(new Runnable() {
					
					@Override
					public void run() {
						dl.lblFileSize.setText(String.valueOf(finalValue));		
					}
				});
				
				
			}
		}
		*/
	}
	
	
	public void setProgressDialog(ProgressDialog pgDialog) {
		this.pgDialog = pgDialog;
	}
	
	private void showChoicesDialog() {
		AlertDialog.Builder dialog = new AlertDialog.Builder(this.context);
		dialog.setTitle("Select type");
		if (this.aLinks != null) {
			int i;
			String s[] = new String[this.aLinks.size()];
			for (i = 0; i < this.aLinks.size(); i++) {
				s[i] = this.aLinks.get(i).getLabel();
			}
			dialog.setItems(s, this);
				
		}
	
		dialog.show();
	}
	
	@Override
	protected void onPostExecute(Long result) {
		super.onPostExecute(result);
		this.pgDialog.dismiss();
		if (result == 0) {
			
			this.showChoicesDialog();	
		} else {
			AlertDialog.Builder a = new AlertDialog.Builder(this.context);
			a.setTitle("Some Error");
			a.setMessage("Something wrong");
			a.show();
		}
		
	}
	
	public int loadChoices() {
		HttpClient httpClient = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(this.firstUrl);
		
		try {
			//List<NameValuePair> arrHeaders = new ArrayList<NameValuePair>();
						 
			httpGet.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
			httpGet.addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
			httpGet.addHeader("Accept-Encoding", "gzip,deflate,sdch");
			httpGet.addHeader("Connection", "keep-alive");
			httpGet.addHeader("Accept-Language", "th,en-US;q=0.8,en;q=0.6");
			httpGet.addHeader("Host", "www.youtube.com");
			httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4");
			
			
			HttpResponse originalResponse = httpClient.execute(httpGet);
						
			Header encHeader = originalResponse.getEntity().getContentEncoding();
			
			HttpEntity entity = originalResponse.getEntity();
			
			if (encHeader != null) {
				for (HeaderElement he : encHeader.getElements()) {
					if (he.getName().equalsIgnoreCase("gzip")) {
						originalResponse.setEntity(new GzipDecompressingEntity(entity));
					}
				}
			}
			
			String returnStt = ""; 
			//returnStt = EntityUtils.toString(originalResponse.getEntity());
			BufferedReader reader = new BufferedReader(new InputStreamReader(originalResponse.getEntity().getContent()));
			StringBuffer sb = new StringBuffer();
			
			for (String line = null; (line = reader.readLine()) != null;) {
				sb.append(line).append("\r\n");
				if (line.contains("var swf =")) {					
					String varSwf = line;
					varSwf = this.getInsideQuote(varSwf, '"', 0);
				
					
					//byte[] utf8 = varSwf.getBytes("UTF-8");
					//varSwf = new String(utf8);
					varSwf = org.apache.commons.lang3.StringEscapeUtils.unescapeJava(varSwf);
					
					
					String value = this.getValue(varSwf,  "flashvars", '"');
					value = value.replace("%25", "%");
					value = URLDecoder.decode(value);
					
					Object objs[] = this.getValueFrom(value, 0, "url_encoded_fmt_stream_map", "&amp;");
					String urlValue = (String) objs[0];
					
					int lastEndIndex = 0;
					String url = "";
					ArrayList<String> aUrl = new ArrayList<String>();
					this.aLinks = new ArrayList<RealLink>();
					
					String query = urlValue.substring("url_encoded_fmt_stream_map=".length());
					String keyword = query.split("=")[0];
					int lastIndex = 0;
					Object obj[] = this.getValueFrom(query, lastIndex, keyword, "," + keyword);
					String urlXX = (String) obj[0];
					lastIndex = (Integer) obj[1];
					
					while (urlXX.equals("") == false) {
						Log.i(logName, "urlXX=" + urlXX);
						int urlPos = urlXX.indexOf("&url");
						String prefix = "";
						
						if ( (urlPos == -1) && (keyword.equals("url")) ) urlPos = 0;
						prefix = urlXX.substring(0, urlPos);
						Log.d(logName, "prefix=" + prefix);
						
						String postfix = (String) this.getValueFrom(urlXX, 0, "url", "sdfasdf")[0];
						Log.d(logName, "postfix=" + postfix);
						
						String realUrl = postfix.substring("url=".length()) + "&" + prefix;
						realUrl = realUrl.replace("&sig", "&signature");
						RealLink r = new RealLink(realUrl);
						
						realUrl = this.getRealUrl(realUrl);
						Log.i(logName, "realUrl=" + realUrl);
						
						aUrl.add(realUrl);						
						r.updateUrl(realUrl);
						
						this.aLinks.add(r);
						
						obj = this.getValueFrom(query, lastIndex, keyword, "," + keyword);
						urlXX = (String) obj[0];
						lastIndex = (Integer) obj[1];
					}
					
				} else if (line.contains("og:title") == true) {
					this.title = this.getValue(line, "content", '"');
					Log.d(logName, "og:title=" + this.title);
				}
			}
			
			returnStt = sb.toString();
			//Log.d(logName, returnStt);
			//this.showChoicesDialog();
			return(0);
		} catch (Exception e) {
			Log.e(logName, e.toString());
			e.printStackTrace();
			return(-1);
		}
	}
	
	private Map<String, String> getMapFromQuery(String query) {
		Map<String, String> m = new LinkedHashMap<String, String>();
		
		String[] s1 = query.split("&");		
		for (String s2 : s1) {
			String name = s2.split("=")[0];
			String value = "";
			
			int pos = s2.indexOf("=");
			if (pos != -1) {
				value = s2.substring(pos+1);
			}
			
			m.put(name, value);
			Log.d(logName, "added nv: " + name + ": " + value);
		}
		
		return(m);
		
	}
	
	private String getRealUrl(String draftUrl) {
		
		Uri uri = Uri.parse(draftUrl);
		String finalUrl = "";
		
		String baseUrl = uri.getScheme() + "://" + uri.getHost() + uri.getPath() + "?";
		finalUrl = baseUrl;
		Log.d(logName, "baseUrl: " + baseUrl);
		
		String query = draftUrl.substring(baseUrl.length());
		Log.d(logName, "using query: " + query);
		
		int i = 0;
		boolean gotSignature = false;
		Map<String, String> m = this.getMapFromQuery(query);
		for (String param : PARAMS) {
			boolean foundParam = false;
			String value = m.get(param);
			
			if (m.containsKey(param)) {
				foundParam = true;
				if (i > 0) finalUrl = finalUrl + "&";
				
				if (value.equals("signature")) {
					gotSignature = true;
				}
			}
			
			if (foundParam) {
				finalUrl = finalUrl + param + "=" + value;
			}
			
			i += 1;
		}

		return(finalUrl);
		
	}
	
	private Object[] getValueFrom(String line, int initialIndex, String fromKey, String untilStt) {
		Object[] returnObjs = new Object[2];
		returnObjs[0] = "";
		returnObjs[1] = 0;
		
		int lastEndIndex;
		int startIdx = line.indexOf(fromKey, initialIndex);
		if (startIdx == -1) return(returnObjs);
		
		int endIdx = line.indexOf(untilStt, startIdx+1);
		if (endIdx == -1) {
			endIdx = line.length();
		}
		
		lastEndIndex = endIdx;
		
		String outputStt = line.substring(startIdx, endIdx);
		
		returnObjs[0] = outputStt;
		returnObjs[1] = lastEndIndex;
		
		return(returnObjs);
	}
	
	private String getValue(String line, String key, char quoteChar) {
		int startIdx = line.indexOf(key);
		if (startIdx == -1) return("");
		
		int startPos = 0, endPos = 0;
		boolean found = false;
		
		int i;
		
		for (i = startIdx; i < line.length(); i++) {
			if (line.charAt(i) == quoteChar) {
				found = true;
				startPos = i;
				break;
			}
		}
		
		if (found == false) return("");
		found = false;
		
		for (i = startPos+1; i < line.length(); i++) {
			if (line.charAt(i) == quoteChar) {
				found = true;
				endPos = i;
				break;
			}
		}
		
		Log.d(logName, "startPos=" + String.valueOf(startPos) + ", endPos=" + String.valueOf(endPos));
		
		String stt = line.substring(startPos+1, endPos);
		return(stt);
	}
		
	private String getInsideQuote(String line, char quoteChar, int startIdx) {
		int startPos = 0, endPos = 0;
		int i;
		boolean found = false;
		String insideStt = "";
		
		for (i = 0; i < line.length(); i++) {
			if (line.charAt(i) == quoteChar) {
				found = true;
				startPos = i;
				break;
			}
		}
		
		if (found == false) return("");
		
		for (i = line.length()-1; i >= startIdx; i--) {
			Log.d(logName, ">> " + line.substring(i));
			if (line.charAt(i) == quoteChar) {
				found = true;
				endPos = i;
				Log.d(logName, "break");
				break;
				
			}
		}
		
		Log.d(logName, "(getInsideQuote) startPos=" + startPos);
		Log.d(logName, "(getInsideQuote) endPos=" + endPos);
		
		insideStt = line.substring(startPos+1, endPos);
		
		Log.d(logName, "(getInsideQuote) last200=" + insideStt.substring(insideStt.length()-200));
						
		return(insideStt);
	}

	@Override
	protected Long doInBackground(String... params) {
		Log.d(logName, "Executing by " + params[0]);
		int result = 0;
		
		if (params[0].equals("0")) {
			result = this.loadChoices();
		} else if (params[0].equals("1")) {
			String finalUrl = params[1];
			String fileName = params[2];
			
			YoutubeSQLRecord r = new YoutubeSQLRecord();
			r.setId(System.currentTimeMillis());
			r.setFinalUrl(finalUrl);
			r.setOriginalUrl(this.firstUrl);
			r.setTitle(this.title);
			
			
			Log.i(logName, "doInBackGround, finalUrl=" + finalUrl);
			this.dl = new SmartHTTPDownload(this.context, finalUrl);
			dl.setSQLRecord(r);
			HTTPProxyService.fileListItems.add(dl);
			dl.setParent(this);
			dl.execute("0", "", fileName);
			
			HTTPProxyService h  = HTTPProxyService.getInstance();
			h.arrDownloading.add(this.dl);
			
			Log.i(logName, "Added SmartHTTPDownload into fileListItems");
		}
		
		return Long.valueOf(result);
	}
	


	@Override
	public void onClick(DialogInterface dialog, int which) {
		dialog.dismiss();
		YoutubeActivity parent = (YoutubeActivity) this.context;
		
		
		RealLink rl = this.aLinks.get(which);
		String finalUrl = rl.getUrl();
		String fileName = rl.getFileName(this.youtubeQString);
		
		Log.d(logName, "onClick, finalUrl=" + finalUrl + ", fileName=" + fileName);
		
		//parent.startDownload(finalUrl, fileName);
		HTTPProxyService.getInstance().startDownload(finalUrl, fileName, this.firstUrl);
	}
	
	@Override
	protected void onProgressUpdate(Integer... progress) {
		Log.d(logName, "onProgessUpdate, len=" + String.valueOf(progress.length));
				
		for (Integer i : progress) {
			Log.d(logName, String.valueOf(i.intValue()));
			if (this.dl != null) {
				if (this.dl.lblFileSize != null) {
					this.dl.lblFileSize.setText(String.valueOf(i.intValue()));		
				}
				
				if (this.dl.pgbFileDownload != null) {
					this.dl.pgbFileDownload.setProgress(i);
				}
			}
			
		}
	}
	
	
	
}
